package com.yumo.kangchenjunga.settlement;

import java.io.IOException;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import javax.transaction.Transactional;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.yumo.kangchenjunga.activity.ActivityService;
import com.yumo.kangchenjunga.activity.NoSuchActivityException;
import com.yumo.kangchenjunga.company.CompanyService;
import com.yumo.kangchenjunga.company.CompanyVo;
import com.yumo.kangchenjunga.company.NoSuchCompanyException;

import cn.leafcraft.utils.webutil.datetime.DateTimeUtils;

@Service
public class SettlementService {

	private Logger logger = LoggerFactory.getLogger(getClass());

	@Autowired
	private StatementDetailRepository statementDetailRepository;
	@Autowired
	private StatementEntryRepository statementEntryRepository;
	@Autowired
	private CompanyService companyService;
	@Autowired
	private ActivityService activityService;

	public LocalDate settleStartDate(int companyId) {
		StatementEntryEntity entity = statementEntryRepository.findFirstByCompanyIdOrderByEndDateDesc(companyId);

		if (entity != null) {
			return entity.endDate.plusDays(1);
		} else {
			return LocalDate.EPOCH;
		}
	}

	public LocalDate defaultSettleEndDate(int companyId) {
		Objects.isNull(Integer.valueOf(companyId));

		return DateTimeUtils.localDateNow().minusMonths(1).with(TemporalAdjusters.lastDayOfMonth());
	}

	public StatementVo settlePreview(int companyId, LocalDate startDate, LocalDate endDate)
			throws SettleViolationException, NoSuchCompanyException {
		if (statementEntryRepository.countByDate(companyId, startDate, endDate) == 0) {
			CompanyVo company = companyService.queryById(companyId);
			Instant now = DateTimeUtils.instantNow();
			var result = statementDetailRepository.queryDetails(companyId, startDate, endDate);
			var entry = new StatementEntryEntity(company.id, company.name, now, startDate, endDate, BigDecimal.ZERO);
			var details = result.stream().map(it -> {
				try {
					var activity = activityService.queryById(it.getActivityId());

					return new StatementDetailVo(it.getCompanyId(), it.getCompanyName(), it.getStoreId(),
							it.getStoreName(), it.getActivityId(), it.getActivityTitle(), activity.price,
							BigDecimal.valueOf(it.getQuantity()),
							activity.price.multiply(BigDecimal.valueOf(it.getQuantity())));
				} catch (NoSuchActivityException e) {
					logger.error("", e);
					return null;
				}
			}).filter(Objects::nonNull).collect(Collectors.toList());

			entry.amount = sum(details);

			return new StatementVo(entry, details);
		}

		throw new SettleViolationException("结算日期重叠。");
	}

	private BigDecimal sum(List<StatementDetailVo> details) {
		return details.stream().map(it -> it.amount).reduce(BigDecimal.ZERO, (a, b) -> a.add(b));
	}

	@Transactional
	public synchronized StatementVo settle(int companyId, LocalDate startDate, LocalDate endDate)
			throws SettleViolationException, NoSuchCompanyException {
		StatementVo vo = settlePreview(companyId, startDate, endDate);
		var entry = vo.entry;

		entry = statementEntryRepository.saveAndFlush(entry);

		int statementEntryId = entry.getId();
		var details = vo.details.stream().map(it -> new StatementDetailEntity(statementEntryId, it.storeId,
				it.storeName, it.activityId, it.activityTitle, it.price, it.quantity, it.amount))
				.collect(Collectors.toList());

		statementEntryRepository.saveAndFlush(entry);
		statementDetailRepository.saveAll(details);

		return vo;
	}

	public String genExportFilename(int companyId, LocalDate startDate, LocalDate endDate)
			throws NoSuchCompanyException {
		var company = companyService.queryById(companyId);

		return String.format("%d-%s-%s-%s.xlsx", companyId, company.name,
				startDate.format(DateTimeFormatter.BASIC_ISO_DATE), endDate.format(DateTimeFormatter.BASIC_ISO_DATE));
	}

	public void exportSettlePreview(int companyId, LocalDate startDate, LocalDate endDate, OutputStream out)
			throws IOException, SettleViolationException, NoSuchCompanyException {
		try (Workbook workbook = WorkbookFactory.create(true)) {
			var sheet = workbook.createSheet();
			var result = settlePreview(companyId, startDate, endDate);

			{
				Row row = sheet.createRow(0);
				Cell cell;

				cell = row.createCell(0);
				cell.setCellValue("序号");
				cell.setCellType(CellType.STRING);
				cell = row.createCell(1);
				cell.setCellValue("企业ID");
				cell.setCellType(CellType.STRING);
				cell = row.createCell(2);
				cell.setCellValue("企业名称");
				cell.setCellType(CellType.STRING);
				cell = row.createCell(3);
				cell.setCellValue("门店ID");
				cell.setCellType(CellType.STRING);
				cell = row.createCell(4);
				cell.setCellValue("门店名称");
				cell.setCellType(CellType.STRING);
				cell = row.createCell(5);
				cell.setCellValue("权益");
				cell.setCellType(CellType.STRING);
				cell = row.createCell(6);
				cell.setCellValue("结算数量");
				cell.setCellType(CellType.STRING);
				cell = row.createCell(7);
				cell.setCellValue("结算单价");
				cell.setCellType(CellType.STRING);
				cell = row.createCell(8);
				cell.setCellValue("结算金额");
				cell.setCellType(CellType.STRING);
			}

			for (int i = 0; i < result.details.size(); ++i) {
				Row row = sheet.createRow(i + 1);
				Cell cell;

				cell = row.createCell(0);
				cell.setCellValue(i + 1);
				cell.setCellType(CellType.NUMERIC);
				cell = row.createCell(1);
				cell.setCellValue(result.details.get(i).companyId);
				cell.setCellType(CellType.NUMERIC);
				cell = row.createCell(2);
				cell.setCellValue(result.details.get(i).companyName);
				cell.setCellType(CellType.STRING);
				cell = row.createCell(3);
				cell.setCellValue(result.details.get(i).storeId);
				cell.setCellType(CellType.NUMERIC);
				cell = row.createCell(4);
				cell.setCellValue(result.details.get(i).storeName);
				cell.setCellType(CellType.STRING);
				cell = row.createCell(5);
				cell.setCellValue(result.details.get(i).activityTitle);
				cell.setCellType(CellType.STRING);
				cell = row.createCell(6);
				cell.setCellValue(result.details.get(i).quantity.doubleValue());
				cell.setCellType(CellType.NUMERIC);
				cell = row.createCell(7);
				cell.setCellValue(result.details.get(i).price.doubleValue());
				cell.setCellType(CellType.NUMERIC);
				cell = row.createCell(8);
				cell.setCellValue(result.details.get(i).amount.doubleValue());
				cell.setCellType(CellType.NUMERIC);
			}

			Row row = sheet.createRow(result.details.size() + 1);
			Cell cell;

			cell = row.createCell(0);
			cell.setCellValue("总计");
			cell.setCellType(CellType.STRING);
			cell = row.createCell(1);
			cell.setCellValue(result.entry.companyId);
			cell.setCellType(CellType.NUMERIC);
			cell = row.createCell(2);
			cell.setCellValue(result.entry.companyName);
			cell.setCellType(CellType.STRING);
			cell = row.createCell(8);
			cell.setCellValue(result.entry.amount.doubleValue());
			cell.setCellType(CellType.NUMERIC);

			sheet.autoSizeColumn(0);
			sheet.autoSizeColumn(1);
			sheet.autoSizeColumn(2);
			sheet.autoSizeColumn(3);
			sheet.autoSizeColumn(4);
			sheet.autoSizeColumn(5);
			sheet.autoSizeColumn(6);
			sheet.autoSizeColumn(7);
			sheet.autoSizeColumn(8);

			workbook.write(out);
		}
	}

}
